#if (FEATURE_MODE == 0) && defined E_UNIT
#if defined(TSINGMA_MX) || defined(TSINGMA_GX)


#include "sal.h"
#include "ctc_error.h"
#include "ctc_debug.h"
#include "ctc_chip.h"

#include "drv_api.h"
#include "sys_usw_eunit.h"
#include "sys_usw_chip.h"
#include "sys_usw_interrupt.h"
#include "sys_usw_g8031.h"


#define SYS_EUNIT_TIME_OUT  5000
#define SYS_TMM_EUNIT_MAX_HW_LOCK_ID 8

#define M_UNTT_ADDR_BASE 196608 /*MCPU image base: 32768*6 = 196608, N0.7 is misc MCU*/

/* HCPU can read/write ECPU memory by EcpuMem_t, the address is 0x82800000 */
#define SYS_TMM_ECPU_MEM_BASE 0x82800000
#define SYS_TMM_ECPU_MEM_MASK 0x3FFFF /* 256 KB */
/* HCPU can read/write SCPU memory by ScpuMem_t, the address is 0x82880000 */
#define SYS_TMM_SCPU_MEM_BASE 0x82880000
#define SYS_TMM_SCPU_MEM_MASK 0x1FFFF /* 128 KB */

/* mapping ecpu/scpu address to chip address */
#define SYS_TMM_ECPU_ADDR_MAP(ecpu_sys_mem) (((ecpu_sys_mem) & SYS_TMM_ECPU_MEM_MASK) | SYS_TMM_ECPU_MEM_BASE)
#define SYS_TMM_SCPU_ADDR_MAP(scpu_sys_mem) (((scpu_sys_mem) & SYS_TMM_SCPU_MEM_MASK) | SYS_TMM_SCPU_MEM_BASE)

#define SYS_TMM_EUNIT_DMA_RX_RING_BASE 0
#define SYS_TMM_EUNIT_DMA_RX_RING_NUM 4
#define SYS_TMM_EUNIT_DMA_TX_RING_BASE 4
#define SYS_TMM_EUNIT_DMA_TX_RING_NUM 4

/* ECPU DMA ring
 * 0-3:   DmaPktRx
 * 4-7:   DmaPktTx
 * 8-11:  DmaRegRd
 * 12-13: DmaRegWr
 * 14-21: DmaInfo
 */
#define SYS_TMM_ECPU_DMA_REG_RD_RING_BASE 8
#define SYS_TMM_ECPU_DMA_REG_RD_RING_NUM 4
#define SYS_TMM_ECPU_DMA_REG_WR_RING_BASE 12
#define SYS_TMM_ECPU_DMA_REG_WR_RING_NUM 2
#define SYS_TMM_ECPU_DMA_INFO_RING_BASE 14
#define SYS_TMM_ECPU_DMA_INFO_RING_NUM 8
#define SYS_TMM_ECPU_DMA_RING_NUM 22

/* SCPU DMA ring
 * 0-3:   DmaPktRx
 * 4-7:   DmaPktTx
 */
#define SYS_TMM_SCPU_DMA_RING_NUM 8

extern sys_usw_eunit_master_t* p_usw_eunit_master[CTC_MAX_LOCAL_CHIP_NUM_PP];

extern int32
drv_usw_chip_write_ext(uint8 lchip, uint64 offset, uint32* p_value, uint32 length);

extern int32
drv_usw_chip_read_ext(uint8 lchip, uint64 offset, uint32* p_value, uint32 length);

enum sys_tmm_eunit_irq_id_e
{
    SYS_EUNIT_IRQ_HEART = 0,
    SYS_EUNIT_IRQ_ERROR_1 = 1,

    SYS_EUNIT_IRQ_G8031_MIS_GRP0 = 32,
    SYS_EUNIT_IRQ_G8031_MIS_GRP1,
    SYS_EUNIT_IRQ_G8031_MIS_GRP2,
    SYS_EUNIT_IRQ_G8031_STATE_CHANGE_GRP0 = 35,
    SYS_EUNIT_IRQ_G8031_STATE_CHANGE_GRP1,
    SYS_EUNIT_IRQ_G8031_STATE_CHANGE_GRP2,
    SYS_EUNIT_IRQ_G8031_STATE_APS_SWITCH_GRP0 = 38,
    SYS_EUNIT_IRQ_G8031_STATE_APS_SWITCH_GRP1,
    SYS_EUNIT_IRQ_G8031_STATE_APS_SWITCH_GRP2,

    SYS_EUNIT_IRQ_NPM_IM_LOSS_PROFILE1=64,
    SYS_EUNIT_IRQ_NPM_IM_LOSS_PROFILE2,
    SYS_EUNIT_IRQ_NPM_IM_LOSS_PROFILE3,
    SYS_EUNIT_IRQ_NPM_IM_LOSS_PROFILE4,
    SYS_EUNIT_IRQ_NPM_IM_LOSS_PROFILE5,
    SYS_EUNIT_IRQ_NPM_IM_LOSS_PROFILE6,
    SYS_EUNIT_IRQ_NPM_IM_LOSS_PROFILE7,

    SYS_EUNIT_IRQ_MAX = 128
};

/*for misc mcpu*/
enum sys_tmm_eunit_irq_id_m_e
{
    SYS_EUNIT_IRQ_M_CODE_READY = 0,

    SYS_EUNIT_IRQ_MAX_M = 128
};

struct sys_tmm_eunit_dma_info_s
{
    uint16 rx_cur_idx[SYS_TMM_EUNIT_DMA_RX_RING_NUM];
    uint32 rx_use_bmp;
    uint16 tx_cur_idx[SYS_TMM_EUNIT_DMA_TX_RING_NUM];
    uint32 tx_use_bmp;
};
typedef struct sys_tmm_eunit_dma_info_s sys_tmm_eunit_dma_info_t;

enum sys_tmm_eunit_cfg_type_e
{
    /* internal use */
    SYS_TMM_EUNIT_CFG_LED,
    SYS_TMM_EUNIT_CFG_LED_MAPPING,
    SYS_TMM_EUNIT_CFG_G8031,
    SYS_TMM_EUNIT_CFG_MPLS_IM,
    SYS_TMM_EUNIT_CFG_DBG,
    SYS_TMM_EUNIT_DMA_INFO,
    SYS_TMM_EUNIT_CFG_HW_RESET,
    SYS_TMM_EUNIT_CFG_APP_STATUS,
    SYS_TMM_EUNIT_CFG_EMIC_VER,
    SYS_TMM_EUNIT_DUMP_THREAD_INFO,
    SYS_TMM_EUNIT_MEM_INFO,

    SYS_TMM_EUNIT_CFG_TYPE_MAX = CTC_EUNIT_CFG_TYPE_CUSTOM_BASE
};
typedef enum sys_tmm_eunit_cfg_type_e sys_tmm_eunit_cfg_type_t;

enum sys_tmm_eunit_misc_int_type_e
{
    SYS_TMM_EUNIT_MISC_INT_FEATURES = 0,
    SYS_TMM_EUNIT_MISC_INT_FEATURES_ADDR = 1,
    SYS_TMM_EUNIT_MISC_INT_MGT = 2,
    SYS_TMM_EUNIT_MISC_INT_DBG_BUF_ADDR = 3,
    SYS_TMM_EUNIT_MISC_INT_ALIVE_CNT = 4,
    SYS_TMM_EUNIT_MISC_INT_MPLS_IM = 5,
    SYS_TMM_EUNIT_MISC_INT_G8031 = 6,
    SYS_TMM_EUNIT_MISC_INT_CMD_MEM_ADDR = 7,
    SYS_TMM_EUNIT_MISC_INT_MAX = 8
};
typedef enum sys_tmm_eunit_misc_int_type_e sys_tmm_eunit_misc_int_type_t;


int32
sys_tmm_eunit_hw_lock(uint8 lchip, uint8 eunit_id, uint8 lock_id)
{
    Grant0ExtCtl_m extCtlw, extCtlr;
    uint64 cmdw = 0, cmdr = 0;
    uint32 timeout = 1000;
    uint32 value = 0;
    uint32 tbl_id[] = {Grant0ExtCtl_t, ScpuGrant0ExtCtl_t, McpuGrant0ExtCtl_t};

    CTC_MAX_VALUE_CHECK(lock_id, SYS_TMM_EUNIT_MAX_HW_LOCK_ID);

    sal_memset(&extCtlw, 0,sizeof(extCtlw));
    sal_memset(&extCtlr, 0,sizeof(extCtlr));
    SetGrant0ExtCtl(V, grant0ExtCtl_f, &extCtlw, 0x3);
    cmdw = DRV_IOW(tbl_id[eunit_id] + (Grant1ExtCtl_t - Grant0ExtCtl_t) * lock_id, DRV_ENTRY_FLAG);
    cmdr = DRV_IOR(tbl_id[eunit_id] + (Grant1ExtCtl_t - Grant0ExtCtl_t) * lock_id, DRV_ENTRY_FLAG);

    do {
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmdw, &extCtlw));
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmdr, &extCtlr));
        value = GetGrant0ExtCtl(V, grant0ExtCtl_f, &extCtlr);
        if(value & 0x1)
        {
            break;
        }
        sal_task_sleep(1);
    }while(--timeout);

    if (!timeout)
    {
        return CTC_E_MUTEX_BUSY;
    }

    return CTC_E_NONE;
}

int32
sys_tmm_eunit_hw_unlock(uint8 lchip, uint8 eunit_id, uint8 lock_id)
{
    Grant0ExtCtl_m extCtl;
    uint32 cmd = 0;
    uint32 tbl_id[] = {Grant0ExtCtl_t, ScpuGrant0ExtCtl_t, McpuGrant0ExtCtl_t};

    CTC_MAX_VALUE_CHECK(lock_id, SYS_TMM_EUNIT_MAX_HW_LOCK_ID);
    sal_memset(&extCtl, 0,sizeof(extCtl));
    SetGrant0ExtCtl(V, grant0ExtCtl_f, &extCtl, 0);
    cmd = DRV_IOW(tbl_id[eunit_id] + (Grant1ExtCtl_t - Grant0ExtCtl_t) * lock_id, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &extCtl));

    return CTC_E_NONE;
}

int32
_sys_tmm_eunit_map_isr(uint8 lchip, uint8 irq_id,  uint8* isr_type)
{
    switch (irq_id)
    {
        case SYS_EUNIT_IRQ_HEART:
            *isr_type = SYS_EUNIT_ISR_HEART;
            break;
        case SYS_EUNIT_IRQ_ERROR_1:
            *isr_type = SYS_EUNIT_ISR_ERROR;
            break;
        case SYS_EUNIT_IRQ_G8031_MIS_GRP0:
        case SYS_EUNIT_IRQ_G8031_MIS_GRP1:
        case SYS_EUNIT_IRQ_G8031_MIS_GRP2:
        case SYS_EUNIT_IRQ_G8031_STATE_CHANGE_GRP0:
        case SYS_EUNIT_IRQ_G8031_STATE_CHANGE_GRP1:
        case SYS_EUNIT_IRQ_G8031_STATE_CHANGE_GRP2:
        case SYS_EUNIT_IRQ_G8031_STATE_APS_SWITCH_GRP0:
        case SYS_EUNIT_IRQ_G8031_STATE_APS_SWITCH_GRP1:
        case SYS_EUNIT_IRQ_G8031_STATE_APS_SWITCH_GRP2:
            *isr_type = SYS_EUNIT_ISR_G8031;
            break;
        case SYS_EUNIT_IRQ_NPM_IM_LOSS_PROFILE1:
        case SYS_EUNIT_IRQ_NPM_IM_LOSS_PROFILE2:
        case SYS_EUNIT_IRQ_NPM_IM_LOSS_PROFILE3:
        case SYS_EUNIT_IRQ_NPM_IM_LOSS_PROFILE4:
        case SYS_EUNIT_IRQ_NPM_IM_LOSS_PROFILE5:
        case SYS_EUNIT_IRQ_NPM_IM_LOSS_PROFILE6:
        case SYS_EUNIT_IRQ_NPM_IM_LOSS_PROFILE7:
            *isr_type = SYS_EUNIT_NPM_IM;
            break;
        default:
            break;
    }
    return CTC_E_NONE;
}

int32
_sys_tmm_eunit_map_isr_mcpu(uint8 lchip, uint8 irq_id,  uint8* isr_type)
{
    switch (irq_id)
    {
        case SYS_EUNIT_IRQ_M_CODE_READY:
            *isr_type = SYS_EUNIT_ISR_CODE_READY;
            break;
        default:
            break;
    }
    return CTC_E_NONE;
}


int32
_sys_tmm_eunit_clear_irq_id(uint8 lchip, uint8 unit, uint8 id)
{
    uint32 cmd = 0;
    uint32 value[4] = {0};

    if (id > 127)
    {
        return CTC_E_INVALID_PARAM;
    }
    /*IntrExtCtl*/
    if (unit == SYS_EUNIT_M)
    {
        McpuIntrIntCtl_m intr_ctl;
        sal_memset(&intr_ctl, 0, sizeof(intr_ctl));
        CTC_BMP_SET(value, id);
        SetMcpuIntrIntCtl(A, intrIntCtl_f, &intr_ctl, value);
        cmd = DRV_IOW(McpuIntrIntCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 6, cmd, &intr_ctl));
    }
    else if (unit == SYS_EUNIT_E)
    {
        IntrIntCtl_m intr_ctl;
        sal_memset(&intr_ctl, 0, sizeof(intr_ctl));
        CTC_BMP_SET(value, id);
        SetIntrIntCtl(A, intrIntCtl_f, &intr_ctl, value);
        cmd = DRV_IOW(IntrIntCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &intr_ctl));
    }
    else
    {
        ScpuIntrIntCtl_m intr_ctl;
        sal_memset(&intr_ctl, 0, sizeof(intr_ctl));
        CTC_BMP_SET(value, id);
        SetScpuIntrIntCtl(A, intrIntCtl_f, &intr_ctl, value);
        cmd = DRV_IOW(ScpuIntrIntCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &intr_ctl));
    }

    return CTC_E_NONE;
}


int32
_sys_tmm_eunit_irq_dispatch(uint8 lchip, uint8 unit, uint8 id)
{
    uint8 isr_type = 0;
    sys_usw_eunit_isr_data_t isr_data;
    if (unit == SYS_EUNIT_M)
    {
        _sys_tmm_eunit_map_isr_mcpu(lchip, id, &isr_type);
    }
    else
    {
        _sys_tmm_eunit_map_isr(lchip, id, &isr_type);
    }

    isr_data.unit = unit;
    isr_data.irq_id = id;
    _sys_tmm_eunit_clear_irq_id(lchip, unit, id);
    if (p_usw_eunit_master[lchip]->isr[isr_type])
    {
        p_usw_eunit_master[lchip]->isr[isr_type](lchip, isr_type, &isr_data);
    }

    return CTC_E_NONE;
}



int32
_sys_tmm_eunit_get_mcpu_data_base(uint8 lchip, uint8 mcpu_num, uint32* tbl_idx)
{
    uint32 cmd = 0;
    McpuMiscIntInfo7_m misc_info;

    cmd = DRV_IOR(McpuMiscIntInfo7_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, mcpu_num, cmd, &misc_info));
    *tbl_idx = GetMcpuMiscIntInfo7(V, miscIntInfo7_f, &misc_info);
     return CTC_E_NONE;
}

int32
sys_tmm_eunit_set_mcpu_cfg_flag(uint8 lchip, uint32 flag, uint8 mcpu_num,uint8 val)
{
    uint32 cmd = 0;
    uint32 tmp = 0;
    McpuCommonInfo0_m mcpu_info;

    sal_memset(&mcpu_info, 0, sizeof(McpuCommonInfo0_m));
    cmd = DRV_IOR(McpuCommonInfo0_t + flag / 32, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, mcpu_num, cmd, &mcpu_info));
    tmp = GetMcpuCommonInfo0(V, commonInfo0_f, &mcpu_info);

    cmd = DRV_IOW(McpuCommonInfo0_t + flag / 32, DRV_ENTRY_FLAG);
    val ? CTC_BIT_SET(tmp, flag&0x1F) : CTC_BIT_UNSET(tmp, flag&0x1F);
    SetMcpuCommonInfo0(V, commonInfo0_f, &mcpu_info, tmp);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, mcpu_num, cmd, &mcpu_info));
    return CTC_E_NONE;
}
int32 sys_tmm_eunit_mcpu_write_data(uint8 lchip,uint8 mcpu_num,uint32* p_data,uint32 lenth)
{
    uint32 cmd = 0;
    uint32 tbl_idx = 0;
    uint8  idx = 0;
    McpuMem_m mcpu_mem;

    CTC_PTR_VALID_CHECK(p_data);
    CTC_ERROR_RETURN(_sys_tmm_eunit_get_mcpu_data_base(lchip, mcpu_num, &tbl_idx));
    tbl_idx += (DRV_TABLE_MAX_INDEX(lchip, McpuMem_t) / M_UNTT_MAX_NUM * mcpu_num);
    cmd = DRV_IOW(McpuMem_t, DRV_ENTRY_FLAG);
    for (idx = 0; idx < lenth; idx++)/*word*/
    {
        sal_memset(&mcpu_mem, 0, sizeof(mcpu_mem));
        SetMcpuMem(V, data_f, &mcpu_mem, p_data[idx]);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, tbl_idx + idx, cmd, &mcpu_mem));
    }
    return CTC_E_NONE;
}
int32 sys_tmm_eunit_mcpu_read_data(uint8 lchip,uint8 mcpu_num,uint32* p_data,uint32 lenth)
{
    uint32 cmd = 0;
    uint32 tbl_idx = 0;
    uint8  idx = 0;
    McpuMem_m mcpu_mem;

    CTC_PTR_VALID_CHECK(p_data);
    CTC_ERROR_RETURN(_sys_tmm_eunit_get_mcpu_data_base(lchip, mcpu_num, &tbl_idx));
    tbl_idx += (DRV_TABLE_MAX_INDEX(lchip, McpuMem_t) / M_UNTT_MAX_NUM * mcpu_num);
    cmd = DRV_IOR(McpuMem_t, DRV_ENTRY_FLAG);
    for (idx = 0; idx < lenth; idx++)/*word*/
    {
        sal_memset(&mcpu_mem, 0, sizeof(mcpu_mem));

        CTC_ERROR_RETURN(DRV_IOCTL(lchip, tbl_idx + idx, cmd, &mcpu_mem));
        p_data[idx] = GetMcpuMem(V, data_f, &mcpu_mem);
    }
    return CTC_E_NONE;
}

int32
sys_tmm_eunit_mcpu_set_config(uint8 lchip, uint8 idx, uint32* value)
{
    uint32 cmd = 0;
    uint32 tbl_id = 0;
    McpuMiscExtInfo0_m ext_info;

    tbl_id = McpuMiscExtInfo0_t + (McpuMiscExtInfo1_t - McpuMiscExtInfo0_t)*idx;
    cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, (M_UNTT_MAX_NUM - 1), cmd, &ext_info));
    SetMcpuMiscExtInfo0(V, miscExtInfo0_f, &ext_info, *value);
    cmd = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, (M_UNTT_MAX_NUM - 1), cmd, &ext_info));

    return CTC_E_NONE;
}

int32
sys_tmm_eunit_mcpu_get_config(uint8 lchip, uint8 idx, uint32* value)
{
    uint32 cmd = 0;
    uint32 tbl_id = 0;
    McpuMiscExtInfo0_m ext_info;

    tbl_id = McpuMiscExtInfo0_t + (McpuMiscExtInfo1_t - McpuMiscExtInfo0_t)*idx;
    cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, (M_UNTT_MAX_NUM - 1), cmd, &ext_info));
    *value = GetMcpuMiscExtInfo0(V, miscExtInfo0_f, &ext_info);

    return CTC_E_NONE;
}

int32
sys_tmm_eunit_get_mcpu_cfg_flag(uint8 lchip, uint32 flag, uint8 mcpu_num,uint8* val)
{
    uint32 cmd = 0;
    uint32 tmp = 0;
    McpuCommonInfo0_m mcpu_info;

    sal_memset(&mcpu_info, 0, sizeof(McpuCommonInfo0_m));
    cmd = DRV_IOR(McpuCommonInfo0_t + flag / 32, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, mcpu_num, cmd, &mcpu_info));
    tmp = GetMcpuCommonInfo0(V, commonInfo0_f, &mcpu_info);
    *val = CTC_IS_BIT_SET(tmp, flag &0x1F);
    return CTC_E_NONE;
}

STATIC INLINE int32
_sys_tmm_eunit_misc_int_ctl_read(uint8 lchip, uint8 eunit_id, uint8 type, uint32* value)
{
    uint32 cmd = 0;
    uint32 ecpu_tbl_id[] = {MiscIntInfo0_t, MiscIntInfo1_t, MiscIntInfo2_t, MiscIntInfo3_t, 
                            MiscIntInfo4_t, MiscIntInfo5_t, MiscIntInfo6_t, MiscIntInfo7_t};
    uint32 scpu_tbl_id[] = {ScpuMiscIntInfo0_t, ScpuMiscIntInfo1_t, ScpuMiscIntInfo2_t, ScpuMiscIntInfo3_t, 
                            ScpuMiscIntInfo4_t, ScpuMiscIntInfo5_t, ScpuMiscIntInfo6_t, ScpuMiscIntInfo7_t};
    MiscIntInfo0_m misc_info;

    cmd = DRV_IOR(eunit_id == SYS_EUNIT_E ? ecpu_tbl_id[type] : scpu_tbl_id[type], DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &misc_info));
    *value = GetMiscIntInfo0(V, miscIntInfo0_f, &misc_info);

    return CTC_E_NONE;
}

/* data_len: units: word 
  EcpuMem/ScpuMem only support read/write per entry (4word, refer to drv_ds_tmm.h EcpuMem/ScpuMem
*/
STATIC INLINE int32
_sys_tmm_eunit_write_data(uint8 lchip, uint32 cfg_addr, uint32* p_data, uint32 data_len)
{
    uint32 size_in4word = data_len>>2;
    uint32 ds[4];
    uint32 offset = 0;
    uint32 extra_len = 0;

    /* 16byte-align process if cfg_addr is not 16byte-aligned */
    if (cfg_addr & 0xF)
    {
        drv_usw_chip_read_ext(lchip, cfg_addr & 0xFFFFFFF0, ds, 4);
        extra_len = 16 - (cfg_addr & 0xF);
        extra_len = extra_len < (data_len<<2) ? extra_len : (data_len<<2);
        sal_memcpy(&ds[(cfg_addr & 0xF)>>2], p_data, extra_len);
        drv_usw_chip_write_ext(lchip, cfg_addr & 0xFFFFFFF0, ds, 4);

        /* update buffer after writing non-16byte-aligned bytes */
        cfg_addr += extra_len;
        p_data += (extra_len>>2);
        data_len -= (extra_len>>2);
        size_in4word = data_len>>2;
    }

    /* 16byte-align write, write 4 word once*/
    while (size_in4word)
    {
        drv_usw_chip_write_ext(lchip, cfg_addr + (offset<<2), &p_data[offset], 4);
        offset += 4;
        size_in4word--;
    }

    /* write extra bytes*/
    if (data_len & 0x3)
    {
        size_in4word = data_len>>2;
        drv_usw_chip_read_ext(lchip, cfg_addr + (size_in4word<<4), ds, 4);
        sal_memcpy(ds, &p_data[size_in4word<<2], (data_len & 0x3)<<2);
        drv_usw_chip_write_ext(lchip, cfg_addr + (size_in4word<<4), ds, 4);
    }
    return CTC_E_NONE;
}

/* data_len: units: word */
STATIC INLINE int32
_sys_tmm_eunit_read_data(uint8 lchip, uint32 cfg_addr, uint32* p_data, uint32 data_len)
{
    uint32 size_in4word = data_len>>2;
    uint32 ds[4];
    uint32 offset = 0;
    uint32 extra_len = 0;

    /* 16byte-align process if cfg_addr is not 16byte-aligned */
    if (cfg_addr & 0xF)
    {
        drv_usw_chip_read_ext(lchip, cfg_addr & 0xFFFFFFF0, ds, 4);
        extra_len = 16 - (cfg_addr & 0xF);
        extra_len = extra_len < (data_len<<2) ? extra_len : (data_len<<2);
        sal_memcpy(p_data, &ds[(cfg_addr & 0xF)>>2], extra_len);

        /* update buffer after reading non-16byte-aligned bytes */
        cfg_addr += extra_len;
        p_data += (extra_len>>2);
        data_len -= (extra_len>>2);
        size_in4word = data_len>>2;
    }

    while (size_in4word)
    {
        drv_usw_chip_read_ext(lchip, cfg_addr + (offset<<2), &p_data[offset], 4);
        offset += 4;
        size_in4word--;
    }

    size_in4word = data_len>>2;
    if (data_len & 0x3)
    {
        drv_usw_chip_read_ext(lchip, cfg_addr + (size_in4word<<4), ds, 4);
        sal_memcpy(&p_data[size_in4word<<2], ds, (data_len & 0x3)<<2);
    }

    return CTC_E_NONE;
}

STATIC int32
_sys_tmm_eunit_is_reset(uint8 lchip, uint8 eunit_id, uint8* value)
{
    uint32 cmd = 0;
    EcpuSoftReset_m soft_rst;
    ScpuSoftReset_m scpu_soft_rst;

    if (eunit_id == SYS_EUNIT_E)
    {
        cmd = DRV_IOR(EcpuSoftReset_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &soft_rst));
        *value = GetEcpuSoftReset(V, cfgResetEcpuCore_f, &soft_rst);
    }
    else if (eunit_id == SYS_EUNIT_S)
    {
        cmd = DRV_IOR(ScpuSoftReset_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &scpu_soft_rst));
        *value = GetScpuSoftReset(V, cfgResetEcpuCore_f, &scpu_soft_rst);
    }

    return CTC_E_NONE;
}

STATIC int32
_sys_tmm_eunit_is_working(uint8 lchip, uint8 eunit_id, uint8* is_working)
{
    uint32 intr_vec[2] = {0};
    uint8 is_reset = 0;
    uint32 offset = 0;

    CTC_ERROR_RETURN(_sys_tmm_eunit_is_reset(lchip, eunit_id, &is_reset));
    if (!is_reset)
    {
        CTC_ERROR_RETURN(_sys_tmm_eunit_misc_int_ctl_read(lchip, eunit_id, SYS_TMM_EUNIT_MISC_INT_ALIVE_CNT, &offset));
        CTC_ERROR_RETURN(_sys_tmm_eunit_read_data(lchip, offset, &intr_vec[0], 1));

        sal_task_sleep(50);

        CTC_ERROR_RETURN(_sys_tmm_eunit_read_data(lchip, offset, &intr_vec[1], 1));

        *is_working = (intr_vec[0] != intr_vec[1]);
    }
    else
    {
        *is_working = 0;
    }

    return CTC_E_NONE;
}

STATIC int32
_sys_tmm_eunit_get_empty_cmd(uint8 lchip, uint32 offset)
{
    sys_eunit_cfg_cmd_t cfg_cmd = {0};
    uint16 timeout = SYS_EUNIT_CMD_TIMEOUT;

    CTC_ERROR_RETURN(_sys_tmm_eunit_read_data(lchip, offset, (uint32*)&cfg_cmd, sizeof(sys_eunit_cfg_cmd_t)/4));
    while (cfg_cmd.valid && --timeout)
    {
        sal_task_sleep(1);
        CTC_ERROR_RETURN(_sys_tmm_eunit_read_data(lchip, offset, (uint32*)&cfg_cmd, sizeof(sys_eunit_cfg_cmd_t)/4));
    }
    if (cfg_cmd.valid)
    {
        return CTC_E_HW_FAIL;
    }
    return CTC_E_NONE;
}

int32
_sys_tmm_eunit_cfg_op_finish(uint8 lchip, uint32 offset)
{
    uint16 timeout = SYS_EUNIT_CMD_TIMEOUT;
    sys_eunit_cfg_cmd_t cfg_cmd = {0};

    do
    {
        /* Get CMD Memory */
        CTC_ERROR_RETURN(_sys_tmm_eunit_read_data(lchip, offset, (uint32*)&cfg_cmd, sizeof(sys_eunit_cfg_cmd_t)/4));
        if (cfg_cmd.done)
        {
            return CTC_E_NONE;
        }
        sal_task_sleep(1);
    }while (--timeout);
    return CTC_E_HW_FAIL;
}

int32
_sys_tmm_eunit_set_usr_config(uint8 lchip, void* p_cfg)
{
    uint32  offset = 0;
    uint8   eunit_id = 0;
    sys_eunit_cfg_cmd_t cfg_cmd = {0};
    ctc_eunit_cfg_t *p_usr_cfg = (ctc_eunit_cfg_t*)p_cfg;
    uint8 eunit_inner_used[] = {0,1,1};/* scpu/mcu7 is reserved for internal used*/
    uint8 eunit_cfg_type =0;
    uint8 is_working;

    CTC_PTR_VALID_CHECK(p_usr_cfg);
    CTC_PTR_VALID_CHECK(p_usr_cfg->p_data);
    CTC_MAX_VALUE_CHECK(p_usr_cfg->eunit_id, MCHIP_CAP(SYS_CAP_EUNIT_NUM) - 1);

    if (CTC_EUNIT_CFG_TYPE_DEBUG == p_usr_cfg->type)
    {
        eunit_cfg_type = SYS_TMM_EUNIT_CFG_DBG;
    }
    else
    {
        CTC_MIN_VALUE_CHECK(p_usr_cfg->type, CTC_EUNIT_CFG_TYPE_CUSTOM_BASE);
        if (eunit_inner_used[p_usr_cfg->eunit_id])
        {
            SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "Eunit %d is reserved, not allowed to get config\n", p_usr_cfg->eunit_id);
            return CTC_E_INVALID_CONFIG;
        }
        eunit_cfg_type = p_usr_cfg->type;
    }

    eunit_id = p_usr_cfg->eunit_id;
    CTC_ERROR_RETURN(_sys_tmm_eunit_is_working(lchip, eunit_id, &is_working));
    if (!is_working)
    {
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "Eunit %d is not working\n", eunit_id);
        return CTC_E_NOT_READY;
    }
    CTC_ERROR_RETURN(_sys_tmm_eunit_misc_int_ctl_read(lchip, eunit_id, SYS_TMM_EUNIT_MISC_INT_CMD_MEM_ADDR, &offset));
    /* Get CMD Memory */
    CTC_ERROR_RETURN(_sys_tmm_eunit_get_empty_cmd(lchip, offset));
    
    cfg_cmd.done     = 0;
    cfg_cmd.op       = SYS_EUNIT_CFG_OP_SET;
    cfg_cmd.data_len = p_usr_cfg->data_len;
    cfg_cmd.type     = eunit_cfg_type;
    CTC_ERROR_RETURN(_sys_tmm_eunit_write_data(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32 *)p_usr_cfg->p_data, cfg_cmd.data_len / 4));

    cfg_cmd.valid = 1;
    CTC_ERROR_RETURN(_sys_tmm_eunit_write_data(lchip, offset, (uint32 *)&cfg_cmd, sizeof(sys_eunit_cfg_cmd_t) / 4));
    CTC_ERROR_RETURN(_sys_tmm_eunit_cfg_op_finish(lchip, offset));

    return CTC_E_NONE;
}

int32
_sys_tmm_eunit_get_usr_config(uint8 lchip, void* p_cfg)
{
    uint32  offset = 0;
    uint8   eunit_id = 0;
    sys_eunit_cfg_cmd_t cfg_cmd = {0};
    ctc_eunit_cfg_t *p_usr_cfg = (ctc_eunit_cfg_t*)p_cfg;
    uint8 eunit_inner_used[] = {0,1,1};/* scpu/mcu7 is reserved for internal used*/
    uint8 eunit_cfg_type =0;
    uint8 is_working;

    CTC_PTR_VALID_CHECK(p_usr_cfg);
    CTC_PTR_VALID_CHECK(p_usr_cfg->p_data);
    CTC_MAX_VALUE_CHECK(p_usr_cfg->eunit_id, MCHIP_CAP(SYS_CAP_EUNIT_NUM) - 1);

    if (CTC_EUNIT_CFG_TYPE_DEBUG == p_usr_cfg->type)
    {
        eunit_cfg_type = SYS_TMM_EUNIT_CFG_DBG;
    }
    else
    {
        CTC_MIN_VALUE_CHECK(p_usr_cfg->type, CTC_EUNIT_CFG_TYPE_CUSTOM_BASE);
        if (eunit_inner_used[p_usr_cfg->eunit_id])
        {
            SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "Eunit %d is reserved, not allowed to get config\n", p_usr_cfg->eunit_id);
            return CTC_E_INVALID_CONFIG;
        }
        eunit_cfg_type = p_usr_cfg->type;
    }

    eunit_id = p_usr_cfg->eunit_id;
    CTC_ERROR_RETURN(_sys_tmm_eunit_is_working(lchip, eunit_id, &is_working));
    if (!is_working)
    {
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "Eunit %d is not working\n", eunit_id);
        return CTC_E_NOT_READY;
    }
    CTC_ERROR_RETURN(_sys_tmm_eunit_misc_int_ctl_read(lchip, eunit_id, SYS_TMM_EUNIT_MISC_INT_CMD_MEM_ADDR, &offset));
    /* Get CMD Memory */
    CTC_ERROR_RETURN(_sys_tmm_eunit_get_empty_cmd(lchip, offset));
    cfg_cmd.done     = 0;
    cfg_cmd.op       = SYS_EUNIT_CFG_OP_GET;
    cfg_cmd.data_len = p_usr_cfg->data_len;
    cfg_cmd.type     = eunit_cfg_type;
    CTC_ERROR_RETURN(_sys_tmm_eunit_write_data(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32 *)p_usr_cfg->p_data, cfg_cmd.data_len / 4));    

    cfg_cmd.valid = 1;
    CTC_ERROR_RETURN(_sys_tmm_eunit_write_data(lchip, offset, (uint32 *)&cfg_cmd, sizeof(sys_eunit_cfg_cmd_t) / 4));
    CTC_ERROR_RETURN(_sys_tmm_eunit_cfg_op_finish(lchip, offset));

    CTC_ERROR_RETURN(_sys_tmm_eunit_read_data(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32 *)p_usr_cfg->p_data, cfg_cmd.data_len / 4));

    return CTC_E_NONE;
}

STATIC int32
_sys_tmm_eunit_get_emic_ver(uint8 lchip, uint8 eunit_id, sys_eunit_emic_ver_t* p_info)
{
    uint32 offset = 0;
    sys_eunit_cfg_cmd_t cfg_cmd = {0};
    CTC_ERROR_RETURN(_sys_tmm_eunit_misc_int_ctl_read(lchip, eunit_id, SYS_TMM_EUNIT_MISC_INT_CMD_MEM_ADDR, &offset));
    /* Get CMD Memory */
    CTC_ERROR_RETURN(_sys_tmm_eunit_get_empty_cmd(lchip, offset));
    cfg_cmd.done    = 0;
    cfg_cmd.op      = SYS_EUNIT_CFG_OP_GET;
    cfg_cmd.type    = SYS_TMM_EUNIT_CFG_EMIC_VER;
    cfg_cmd.valid   = 1;
    cfg_cmd.eunit_id = eunit_id;

    CTC_ERROR_RETURN(_sys_tmm_eunit_write_data(lchip, offset, (uint32 *)&cfg_cmd, sizeof(sys_eunit_cfg_cmd_t) / 4));
    CTC_ERROR_RETURN(_sys_tmm_eunit_cfg_op_finish(lchip, offset));
    CTC_ERROR_RETURN(_sys_tmm_eunit_read_data(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32 *)p_info, sizeof(sys_eunit_emic_ver_t) / 4));

    return CTC_E_NONE;
}

STATIC int32
_sys_tmm_eunit_get_mem_info(uint8 lchip, uint8 eunit_id, sys_eunit_mem_info_t *p_mem_info)
{
    uint32 offset = 0;
    sys_eunit_cfg_cmd_t cfg_cmd = {0};
    
    CTC_ERROR_RETURN(_sys_tmm_eunit_misc_int_ctl_read(lchip, eunit_id, SYS_TMM_EUNIT_MISC_INT_CMD_MEM_ADDR, &offset));
    /* Get CMD Memory */
    CTC_ERROR_RETURN(_sys_tmm_eunit_get_empty_cmd(lchip, offset));
    cfg_cmd.done    = 0;
    cfg_cmd.op      = SYS_EUNIT_CFG_OP_GET;
    cfg_cmd.type    = SYS_TMM_EUNIT_MEM_INFO;
    cfg_cmd.valid   = 1;
    cfg_cmd.eunit_id = eunit_id;

    CTC_ERROR_RETURN(_sys_tmm_eunit_write_data(lchip, offset, (uint32 *)&cfg_cmd, sizeof(sys_eunit_cfg_cmd_t) / 4));
    CTC_ERROR_RETURN(_sys_tmm_eunit_cfg_op_finish(lchip, offset));
    CTC_ERROR_RETURN(_sys_tmm_eunit_read_data(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32 *)p_mem_info, sizeof(sys_eunit_mem_info_t) / 4));

    return CTC_E_NONE;
}

int32
_sys_tmm_eunit_get_dma_info(uint8 lchip, uint8 eunit_id, sys_eunit_dma_info_t* p_info)
{
    uint32 offset = 0;
    sys_eunit_cfg_cmd_t cfg_cmd = {0};
    CTC_ERROR_RETURN(_sys_tmm_eunit_misc_int_ctl_read(lchip, eunit_id, SYS_TMM_EUNIT_MISC_INT_CMD_MEM_ADDR, &offset));
    /* Get CMD Memory */
    CTC_ERROR_RETURN(_sys_tmm_eunit_get_empty_cmd(lchip, offset));
    cfg_cmd.done    = 0;
    cfg_cmd.op      = SYS_EUNIT_CFG_OP_GET;
    cfg_cmd.type    = SYS_TMM_EUNIT_DMA_INFO;
    cfg_cmd.valid   = 1;
    cfg_cmd.eunit_id = eunit_id;
    
    CTC_ERROR_RETURN(_sys_tmm_eunit_write_data(lchip, offset, (uint32 *)&cfg_cmd, sizeof(sys_eunit_cfg_cmd_t) / 4));
    CTC_ERROR_RETURN(_sys_tmm_eunit_cfg_op_finish(lchip, offset));
    CTC_ERROR_RETURN(_sys_tmm_eunit_read_data(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32 *)p_info, sizeof(sys_eunit_dma_info_t) / 4));

    return CTC_E_NONE;
}

STATIC int32
_sys_tmm_eunit_get_app_status(uint8 lchip, void* p_cfg)
{
    uint8 eunit_id  = 0;
    uint32 base     = 0;
    uint32 offset   = 0;
    uint32 info_offset = 0;
    int32 ret = CTC_E_NONE;
    uint8 is_working;
    uint8 idx = 0;
    uint8 app_num = 0;
    ctc_eunit_status_t *app_status = NULL;
    sys_usw_eunit_keepalive_body_t keep_info;
    sys_usw_eunit_app_info_body_t app_info;
    sys_usw_eunit_app_info_hdr_t app_name_hdr;

    app_status = (ctc_eunit_status_t*)p_cfg;
    eunit_id = app_status->eunit_id;

    CTC_MAX_VALUE_CHECK(eunit_id, MCHIP_CAP(SYS_CAP_EUNIT_NUM) - 1);
    CTC_ERROR_RETURN(_sys_tmm_eunit_is_working(lchip, eunit_id, &is_working));
    if (!is_working)
    {
        return CTC_E_NOT_READY;
    }

    CTC_ERROR_RETURN(_sys_tmm_eunit_misc_int_ctl_read(lchip, eunit_id, SYS_TMM_EUNIT_MISC_INT_FEATURES_ADDR, &offset));
    CTC_ERROR_RETURN(_sys_tmm_eunit_read_data(lchip, offset, (uint32*)&app_name_hdr, 1));
    app_num = app_name_hdr.app_num;

    for(idx = 0; idx<app_num; idx++)
    {
        info_offset = (offset + 4) + idx*sizeof(sys_usw_eunit_app_info_body_t);

        sal_memset(&app_info, 0, sizeof(app_info));
        CTC_ERROR_RETURN(_sys_tmm_eunit_read_data(lchip, info_offset, (uint32*)&app_info, sizeof(sys_usw_eunit_app_info_body_t)/4));

        if(app_info.app_id == app_status->app_id)
        {
            break;
        }
    }

    if(idx == app_num)
    {
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "invalid app_id:%d\n", app_status->app_id);
        return CTC_E_INVALID_PARAM;
    }

    CTC_ERROR_RETURN(_sys_tmm_eunit_misc_int_ctl_read(lchip, eunit_id, SYS_TMM_EUNIT_MISC_INT_ALIVE_CNT, &base));
    offset = (base + 4) + app_status->app_id*sizeof(sys_usw_eunit_keepalive_body_t); /*eunit_keepalive_body_t*/
    CTC_ERROR_RETURN(_sys_tmm_eunit_read_data(lchip, offset, (uint32*)&keep_info, 1));

    app_status->alive_cnt = keep_info.alive_cnt;

    return ret;
}

STATIC int32
_sys_tmm_eunit_dump_thread_info(uint8 lchip, uint8 eunit_id)
{
    uint32 offset = 0;
    uint8 index = 0;
    sys_eunit_cfg_cmd_t cfg_cmd = {0};
    sys_usw_eunit_thread_info_list_t info_list;
    char* str_stat[] = {"init", "ready", "suspend", "runing", "close"};

    CTC_ERROR_RETURN(_sys_tmm_eunit_misc_int_ctl_read(lchip, eunit_id, SYS_TMM_EUNIT_MISC_INT_CMD_MEM_ADDR, &offset));
    CTC_ERROR_RETURN(_sys_tmm_eunit_get_empty_cmd(lchip, offset));

    cfg_cmd.done    = 0;
    cfg_cmd.type    = SYS_TMM_EUNIT_DUMP_THREAD_INFO;
    cfg_cmd.op      = SYS_EUNIT_CFG_OP_GET;
    cfg_cmd.valid   = 1;
    
    CTC_ERROR_RETURN(_sys_tmm_eunit_write_data(lchip, offset, (uint32 *)&cfg_cmd, sizeof(sys_eunit_cfg_cmd_t) / 4));
    CTC_ERROR_RETURN(_sys_tmm_eunit_cfg_op_finish(lchip, offset));
    CTC_ERROR_RETURN(_sys_tmm_eunit_read_data(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32*)&info_list, sizeof(sys_usw_eunit_thread_info_list_t)/4));
    if (!info_list.info_num)
    {
        return CTC_E_NONE;
    }
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\nindex(%-u) %-20s  %-10s  %-10s %-10s %-8s %-4s\n", info_list.info_num, "ThreadName", "Func", "Stack", "StackSize", "Stat", "Prio");

    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "----------------------------------------------------------------------------\n");
    for (index = 0; index < info_list.info_num; index++)
    {
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-8u %-20s  0x%08x  0x%08x %-10u %-8s %-4u\n", index, info_list.info[index].name,
                                                                                       info_list.info[index].sp,
                                                                                       info_list.info[index].stack_addr,
                                                                                       info_list.info[index].stack_size,
                                                                                       str_stat[info_list.info[index].stat > 4 ? 0 : info_list.info[index].stat],
                                                                                       info_list.info[index].priority);
    }
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "----------------------------------------------------------------------------\n");
    return CTC_E_NONE;
}


#define ______SYS_MCHIP_API______

int32
sys_tmm_eunit_show_debug_info(uint8 lchip, uint8 eunit_id)
{
    uint32 offset = 0;
    int32 ret = CTC_E_NONE;
    sys_usw_eunit_dbg_hdr_t dbg_hdr = {0};
    char* p_buf;
    char* p_str;
    uint32 idx = 0;

    CTC_MAX_VALUE_CHECK(eunit_id, MCHIP_CAP(SYS_CAP_EUNIT_NUM) - 1);
    CTC_ERROR_RETURN(_sys_tmm_eunit_misc_int_ctl_read(lchip, eunit_id, SYS_TMM_EUNIT_MISC_INT_DBG_BUF_ADDR, &offset));
    if (!offset)
    {
        return CTC_E_NOT_SUPPORT;
    }
    CTC_ERROR_RETURN(_sys_tmm_eunit_read_data(lchip, offset, (uint32*)&dbg_hdr, sizeof(sys_usw_eunit_dbg_hdr_t)/4));
    if (!dbg_hdr.size)
    {
        return CTC_E_NONE;
    }
    p_buf = mem_malloc(MEM_SYSTEM_MODULE, dbg_hdr.size*dbg_hdr.line);
    if (NULL == p_buf)
    {
        return CTC_E_NO_MEMORY;
    }
    ret = _sys_tmm_eunit_read_data(lchip, offset + sizeof(sys_usw_eunit_dbg_hdr_t), (uint32*)p_buf, (dbg_hdr.size*dbg_hdr.line)/4);
    if (ret < 0)
    {
        goto error_back;
    }

    do
    {
        p_str = p_buf + idx * dbg_hdr.size;
        if (!sal_strlen(p_str))
        {
            continue;
        }
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%s\n", p_str);
    }while(++idx < dbg_hdr.line);

error_back:
    mem_free(p_buf);
    return ret;
}


#include "sys_tmm_eunit_e.inc"
#include "sys_tmm_eunit_s.inc"
#include "sys_tmm_eunit_m.inc"
int32
sys_tmm_eunit_load_image(uint8 lchip, uint8 unit, ctc_eunit_install_t* p_eunit)
{
    uint32 size_b = 0;
    uint32 size_w = 0;
    uint32* value_addr = 0;
    uint32 i = 0;
    uint32 idx = 0;
    uint32 cmd = 0;
    EcpuMem_m e_mem;
    McpuMem_m m_mem;


    if (p_eunit && p_eunit->bin_data)
    {
        size_b = p_eunit->bin_size;
        size_w = size_b / 4;
        value_addr = p_eunit->bin_data;
    }
    else
    {
        size_b = (unit == SYS_EUNIT_M) ? sizeof(g_tmm_eunit_m_bin) : (unit == SYS_EUNIT_E) ? sizeof(g_tmm_eunit_e_bin) : sizeof(g_tmm_eunit_s_bin);
        size_w = size_b / 4;
        value_addr = (unit == SYS_EUNIT_M) ? g_tmm_eunit_m_bin : (unit == SYS_EUNIT_E) ? g_tmm_eunit_e_bin : g_tmm_eunit_s_bin;
    }
    if(unit == SYS_EUNIT_M)
    {
        sal_memset(&m_mem, 0, sizeof(McpuMem_m));
        cmd = DRV_IOW(McpuMem_t, DRV_ENTRY_FLAG);

        for (i = 0; i < size_w/4; i++)
        {
            SetMcpuMem(V, data_f, &m_mem, value_addr[i]);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, i + M_UNTT_ADDR_BASE, cmd, &m_mem));
        }
    }
    else
    {
        sal_memset(&e_mem, 0, sizeof(EcpuMem_m));
        cmd = DRV_IOW((unit == SYS_EUNIT_E) ? EcpuMem_t : ScpuMem_t, DRV_ENTRY_FLAG);

        for (i = 0; i < size_w/4; i++)
        {
            SetEcpuMem(V, data0_f, &e_mem, value_addr[i * 4]);
            SetEcpuMem(V, data1_f, &e_mem, value_addr[i * 4 + 1]);
            SetEcpuMem(V, data2_f, &e_mem, value_addr[i * 4 + 2]);
            SetEcpuMem(V, data3_f, &e_mem, value_addr[i * 4 + 3]);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, i, cmd, &e_mem));
        }
        idx = i;
        i = size_w / 4 * 4;
        if (i != size_w)
        {
            sal_memset(&e_mem, 0, sizeof(EcpuMem_m));
            for (; i < size_w; i++)
            {
                SetEcpuMem(V, data0_f + i - (size_w / 4 * 4), &e_mem, value_addr[i]);
            }
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, idx, cmd, &e_mem));
        }
    }
    return CTC_E_NONE;
}

/*SupIntrFunc.funcIntrFromEcpu & SupIntrFunc.funcIntrFromScpu*/
int32
sys_tmm_eunit_isr_handler(uint8 lchip, uint32 intr, void* p_data)
{

    uint8 irq_id = 0;
    uint8 unit = 0;
    uint32 cmd = 0;
    sys_intr_type_t type;
    uint32 intr_bmp[4] = {0};

    if (intr != SYS_INTR_FUNC_ECPU
        && intr != SYS_INTR_FUNC_SCPU
        && intr != SYS_INTR_FUNC_MISC_MCU_REQ)
    {
        return CTC_E_INVALID_PARAM;
    }
    unit = (intr == SYS_INTR_FUNC_MISC_MCU_REQ) ? SYS_EUNIT_M : (intr == SYS_INTR_FUNC_ECPU) ? SYS_EUNIT_E : SYS_EUNIT_S;
    switch (unit)
    {
        case SYS_EUNIT_E:
        {
                IntrIntCtl_m intr_ctl;
                cmd = DRV_IOR(IntrIntCtl_t, DRV_ENTRY_FLAG);
                CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &intr_ctl));
                GetIntrIntCtl(A, intrIntCtl_f, &intr_ctl, intr_bmp);
        }
        break;
       case SYS_EUNIT_S:
        {
                ScpuIntrIntCtl_m intr_ctl;
                cmd = DRV_IOR(ScpuIntrIntCtl_t, DRV_ENTRY_FLAG);
                CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &intr_ctl));
                GetScpuIntrIntCtl(A, intrIntCtl_f, &intr_ctl, intr_bmp);
        }
        break;
        default: /*SYS_EUNIT_M*/
        {
                McpuIntrIntCtl_m intr_ctl;
                cmd = DRV_IOR(McpuIntrIntCtl_t, DRV_ENTRY_FLAG);
                if(DRV_IS_TMG(lchip))
                {
                    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 10, cmd, &intr_ctl));
                }
                else
                {
                    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 6, cmd, &intr_ctl));
                }
                GetMcpuIntrIntCtl(A, intrIntCtl_f, &intr_ctl, intr_bmp);
        }
        break;
    }

    for (irq_id = 0; irq_id < 128; irq_id++)
    {
        if (!CTC_BMP_ISSET(intr_bmp, irq_id))
        {
            continue;
        }
        _sys_tmm_eunit_irq_dispatch(lchip, unit, irq_id);
    }

    sal_memset(&type, 0, sizeof(sys_intr_type_t));
    type.intr = intr;
    sys_usw_interrupt_set_en(lchip, &type, FALSE);

    if ((SYS_EUNIT_M == unit) && DRV_IS_TMG(lchip))
    {
        MCHIP_DMPS_CB(mac_isr_m2c_handler, lchip, 10);
    }
    
    return CTC_E_NONE;
}

int32
sys_tmm_eunit_set_intr(uint8 lchip, uint8 unit, uint8 id)
{
    uint32 cmd = 0;
    uint32 value[4] = {0};

    if (id > 127)
    {
        return CTC_E_INVALID_PARAM;
    }
    /*IntrExtCtl*/
    if (unit == SYS_EUNIT_E)
    {
        IntrExtCtl_m intr_ctl;
        cmd = DRV_IOR(IntrExtCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &intr_ctl));
        GetIntrExtCtl(A, intrExtCtl_f, &intr_ctl, value);
        CTC_BMP_SET(value, id);
        SetIntrExtCtl(A, intrExtCtl_f, &intr_ctl, value);
        cmd = DRV_IOW(IntrExtCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &intr_ctl));
    }
    else if (unit == SYS_EUNIT_S)
    {
        ScpuIntrExtCtl_m intr_ctl;
        cmd = DRV_IOR(ScpuIntrExtCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &intr_ctl));
        GetScpuIntrExtCtl(A, intrExtCtl_f, &intr_ctl, value);
        CTC_BMP_SET(value, id);
        SetScpuIntrExtCtl(A, intrExtCtl_f, &intr_ctl, value);
        cmd = DRV_IOW(ScpuIntrExtCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &intr_ctl));
    }
    return CTC_E_NONE;
}

int32
sys_tmm_eunit_set_cfg(uint8 lchip, uint8 cfg_type, void* p_cfg)
{
    sys_eunit_cfg_cmd_t cfg_cmd = {0};
    sys_eunit_cfg_cmd_t cfg_cmd_scpu = {0};
    uint32 cfg_addr = 0;
    uint32 cfg_addr_scpu = 0;
    uint8 unit = 0;

    switch(cfg_type)
    {
        case SYS_EUNIT_CFG_USER_CFG:
            return _sys_tmm_eunit_set_usr_config(lchip, p_cfg);
        case SYS_EUNIT_CFG_G8031:
        case SYS_EUNIT_CFG_NPM_IM:
        case SYS_EUNIT_CFG_LED:
        case SYS_EUNIT_CFG_LED_MAPPING:
        case SYS_EUNIT_CFG_HW_RESET:
            break;
        default:
            return CTC_E_INVALID_PARAM;
    }

    /* Get config memory address by eunit_id */
    unit = cfg_type == SYS_EUNIT_CFG_G8031 ? SYS_EUNIT_E : SYS_EUNIT_S;
    CTC_ERROR_RETURN(_sys_tmm_eunit_misc_int_ctl_read(lchip, unit, SYS_TMM_EUNIT_MISC_INT_CMD_MEM_ADDR, &cfg_addr));

    /* Check last cmd process done */
    CTC_ERROR_RETURN(_sys_tmm_eunit_get_empty_cmd(lchip, cfg_addr));
    cfg_cmd.op = SYS_EUNIT_CFG_OP_SET;

    /* if do chip reset,  */
    if (SYS_EUNIT_CFG_HW_RESET == cfg_type)
    {
        CTC_ERROR_RETURN(_sys_tmm_eunit_misc_int_ctl_read(lchip, SYS_EUNIT_S, SYS_TMM_EUNIT_MISC_INT_CMD_MEM_ADDR, &cfg_addr_scpu));
        CTC_ERROR_RETURN(_sys_tmm_eunit_get_empty_cmd(lchip, cfg_addr_scpu));
        cfg_cmd_scpu.op = SYS_EUNIT_CFG_OP_SET;
    }

    /* Write config data into config memory */
    switch (cfg_type)
    {
        case SYS_EUNIT_CFG_G8031:
             cfg_cmd.type = SYS_TMM_EUNIT_CFG_G8031;
             CTC_ERROR_RETURN(_sys_tmm_eunit_write_data(lchip, cfg_addr + sizeof(sys_eunit_cfg_cmd_t), (uint32*)p_cfg, sizeof(sys_sc_oam_set_aps_hw_t)/4));
            break;
        case SYS_EUNIT_CFG_NPM_IM:
             cfg_cmd.type = SYS_TMM_EUNIT_CFG_MPLS_IM;
             CTC_ERROR_RETURN(_sys_tmm_eunit_write_data(lchip, cfg_addr + sizeof(sys_eunit_cfg_cmd_t), (uint32*)p_cfg, sizeof(sys_eunit_npm_im_t)/4));
            break;
        case SYS_EUNIT_CFG_LED:
            cfg_cmd.type = SYS_TMM_EUNIT_CFG_LED;
            CTC_ERROR_RETURN(_sys_tmm_eunit_write_data(lchip, cfg_addr + sizeof(sys_eunit_cfg_cmd_t), (uint32*)p_cfg, sizeof(sys_eunit_peri_led_cfg_t)/4));
            break;
        case SYS_EUNIT_CFG_LED_MAPPING:
            cfg_cmd.type = SYS_TMM_EUNIT_CFG_LED_MAPPING;
            CTC_ERROR_RETURN(_sys_tmm_eunit_write_data(lchip, cfg_addr + sizeof(sys_eunit_cfg_cmd_t), (uint32*)p_cfg, sizeof(sys_eunit_peri_led_mapping_t)/4));
            break;
        case SYS_EUNIT_CFG_HW_RESET:
            cfg_cmd.type = SYS_TMM_EUNIT_CFG_HW_RESET;
            cfg_cmd_scpu.type = SYS_TMM_EUNIT_CFG_HW_RESET;
            CTC_ERROR_RETURN(_sys_tmm_eunit_write_data(lchip, cfg_addr + sizeof(sys_eunit_cfg_cmd_t), (uint32*)p_cfg, sizeof(uint32)/4));
            CTC_ERROR_RETURN(_sys_tmm_eunit_write_data(lchip, cfg_addr_scpu + sizeof(sys_eunit_cfg_cmd_t), (uint32*)p_cfg, sizeof(uint32)/4));
            break;
        default:
            return CTC_E_INVALID_PARAM;
    }

    /* Write cmd.valid to trigger ECPU get config data from config memory */
    cfg_cmd.valid = 1;
    CTC_ERROR_RETURN(_sys_tmm_eunit_write_data(lchip, cfg_addr, (uint32*)&cfg_cmd, sizeof(sys_eunit_cfg_cmd_t)/4));

    /* Check ECPU process done */
    CTC_ERROR_RETURN(_sys_tmm_eunit_cfg_op_finish(lchip, cfg_addr));
    if (SYS_EUNIT_CFG_HW_RESET == cfg_type)
    {
        cfg_cmd_scpu.valid = 1;
        CTC_ERROR_RETURN(_sys_tmm_eunit_write_data(lchip, cfg_addr_scpu, (uint32*)&cfg_cmd_scpu, sizeof(sys_eunit_cfg_cmd_t)/4));
        CTC_ERROR_RETURN(_sys_tmm_eunit_cfg_op_finish(lchip, cfg_addr_scpu));
    }
    return CTC_E_NONE;

}

int32
sys_tmm_eunit_get_cfg(uint8 lchip, uint8 cfg_type, void* p_cfg)
{
    uint32 cfg_addr = 0;
    sys_eunit_cfg_cmd_t cfg_cmd = {0};
    uint8 unit = SYS_EUNIT_E;

    switch(cfg_type)
    {
        case SYS_EUNIT_CFG_USER_CFG:
            return _sys_tmm_eunit_get_usr_config(lchip, p_cfg);
        case SYS_EUNIT_CFG_APP_STATUS:
            return _sys_tmm_eunit_get_app_status(lchip, p_cfg);
        case SYS_EUNIT_CFG_G8031:
        case SYS_EUNIT_CFG_NPM_IM:
        case SYS_EUNIT_CFG_LED:
        case SYS_EUNIT_CFG_LED_MAPPING:
        case SYS_EUNIT_CFG_HW_RESET:
            break;
        default:
            return CTC_E_INVALID_PARAM;
    }

    /* find ecpu by cfg_type */
    unit = cfg_type == SYS_EUNIT_CFG_G8031 ? SYS_EUNIT_E : SYS_EUNIT_S;

    /* Get config memory address by eunit_id */
    CTC_ERROR_RETURN(_sys_tmm_eunit_misc_int_ctl_read(lchip, unit, SYS_TMM_EUNIT_MISC_INT_CMD_MEM_ADDR, &cfg_addr));

    /* Check last cmd process done */
    CTC_ERROR_RETURN(_sys_tmm_eunit_get_empty_cmd(lchip, cfg_addr));

    /* Write parameters into config memory for get config */
    switch (cfg_type)
    {
        case SYS_EUNIT_CFG_G8031:
            cfg_cmd.type = SYS_TMM_EUNIT_CFG_G8031;
            break;
        case SYS_EUNIT_CFG_NPM_IM:
            cfg_cmd.type = SYS_TMM_EUNIT_CFG_MPLS_IM;
            break;
        default:
            return CTC_E_NONE;
    }

    /* Write cmd.valid to trigger ECPU set config data into config memory */
    cfg_cmd.op = SYS_EUNIT_CFG_OP_GET;
    cfg_cmd.valid = 1;
    CTC_ERROR_RETURN(_sys_tmm_eunit_write_data(lchip, cfg_addr, (uint32 *)&cfg_cmd, sizeof(sys_eunit_cfg_cmd_t) / 4));
    CTC_ERROR_RETURN(_sys_tmm_eunit_cfg_op_finish(lchip, cfg_addr));
    /* just get enable status for G8031 and MPLS-im */
    CTC_ERROR_RETURN(_sys_tmm_eunit_read_data(lchip, cfg_addr + sizeof(sys_eunit_cfg_cmd_t), (uint32 *)p_cfg, sizeof(uint32) / 4));

    return CTC_E_NONE;

}

int32
sys_tmm_eunit_get_unit_id(uint8 lchip, uint8 cfg_type, uint8* unit)
{
    CTC_PTR_VALID_CHECK(unit);

    switch (cfg_type)
    {
        case SYS_EUNIT_CFG_TSX:
            *unit = SYS_EUNIT_S;
            break;
        case SYS_EUNIT_CFG_TEX:
        case SYS_EUNIT_CFG_IFA:
        case SYS_EUNIT_CFG_NPM_IM:
        case SYS_EUNIT_CFG_G8031:
            *unit = SYS_EUNIT_E;
            break;
        default:
            return CTC_E_INVALID_PARAM;
    }
    return CTC_E_NONE;
}
STATIC int32
_sys_tmm_eunit_load_file(uint8 lchip, uint8 unit, char* file)
{
    char tmp[20];
    sal_file_t fp = NULL;
    uint32 offset = 0;
    uint32 base = 0;
    uint32 value = 0;
    uint32 cmd = 0;
    uint32 tbl_id = 0;
    int32  ret = CTC_E_NONE;
    EcpuMem_m e_mem;
    McpuMem_m m_mem;

    sal_memset(&e_mem, 0, sizeof(EcpuMem_m));
    sal_memset(&m_mem, 0, sizeof(McpuMem_m));
    tbl_id = (unit == SYS_EUNIT_M) ? McpuMem_t : (unit == SYS_EUNIT_E) ? EcpuMem_t : ScpuMem_t;
    cmd = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);

    fp = sal_fopen(file, "r");
    if (fp == NULL)
    {
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "Cannot open file %s\n", file);
        return - 1;
    }

    /* do program */
    offset = 0;
    /*mcpu base: 32768*6 = 196608, N0.7 is misc MCU*/
    base = (unit == SYS_EUNIT_M) ? 196608 : 0;
    while (sal_fgets(tmp, 20, fp) != NULL)
    {
        value = sal_strtou32(tmp, NULL, 16);

        if (unit == SYS_EUNIT_M)
        {


            SetMcpuMem(V, data_f, &m_mem, value);
            CTC_ERROR_GOTO(DRV_IOCTL(lchip, offset + base, cmd, &m_mem), ret, rollback);
        }
        else
        {
            SetEcpuMem(V, data0_f + offset % 4, &e_mem, value);
            if (offset && (0 == (offset + 1) % 4))
            {
                CTC_ERROR_GOTO(DRV_IOCTL(lchip, offset / 4, cmd, &e_mem), ret, rollback);
            }
        }
        offset++;
    }
    if (offset % 4 && unit != SYS_EUNIT_M)
    {
        CTC_ERROR_GOTO(DRV_IOCTL(lchip, offset / 4, cmd, &e_mem), ret, rollback);
    }

    sal_fclose(fp);

    return CTC_E_NONE;
rollback:
    sal_fclose(fp);
    return ret;
}


int32
sys_tmm_eunit_reset(uint8 lchip, uint8 unit, ctc_eunit_install_t* p_eunit)
{
    uint32 cmd = 0;
    SupResetCtl_m sup_rst;
    EcpuSoftReset_m soft_rst;
    ScpuSoftReset_m scpu_soft_rst;
    CtcMiscCtlReset_m mcpu_rst;
    EcpuBootStats_m ecpu_bs;

    if (unit == SYS_EUNIT_E)
    {
        cmd = DRV_IOR(EcpuBootStats_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &ecpu_bs));
        if (1 == GetEcpuBootStats(V, bootAutoModeLog_f, &ecpu_bs))
        {
            return CTC_E_NONE; /*ECPU Start From Flash*/
        }
    }

    if (unit == SYS_EUNIT_M)
    {
        if (!DRV_IS_TMG(lchip))
        {
            cmd = DRV_IOR(CtcMiscCtlReset_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &mcpu_rst));
            SetCtcMiscCtlReset(V, resetCoreMcuIntf_f, &mcpu_rst, 1);
            SetCtcMiscCtlReset(V, resetMcu_f, &mcpu_rst, 1);
            cmd = DRV_IOW(CtcMiscCtlReset_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &mcpu_rst));

            cmd = DRV_IOR(CtcMiscCtlReset_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &mcpu_rst));
            SetCtcMiscCtlReset(V, resetCoreMcuIntf_f, &mcpu_rst, 0);
            cmd = DRV_IOW(CtcMiscCtlReset_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &mcpu_rst));
        }
    }
    else
    {
        /* release E31 general reset */
        cmd = DRV_IOR(SupResetCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &sup_rst));
        cmd = DRV_IOW(SupResetCtl_t, DRV_ENTRY_FLAG);
        if (unit == SYS_EUNIT_E)
        {
            SetSupResetCtl(V, cfgRstEcpuIntf_f, &sup_rst, 1);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &sup_rst));
            SetSupResetCtl(V, cfgRstEcpuIntf_f, &sup_rst, 0);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &sup_rst));
        }
        else if (unit == SYS_EUNIT_S)
        {
            SetSupResetCtl(V, cfgRstScpuIntf_f, &sup_rst, 1);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &sup_rst));
            SetSupResetCtl(V, cfgRstScpuIntf_f, &sup_rst, 0);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &sup_rst));
        }
    }
    if (p_eunit)
    {
        if (!DRV_IS_TMG(lchip))
        {
            if (p_eunit->bin_file)
            {
                CTC_ERROR_RETURN(_sys_tmm_eunit_load_file(lchip, unit, p_eunit->bin_file));
            }
            else
            {
                CTC_ERROR_RETURN(sys_tmm_eunit_load_image(lchip, unit, p_eunit));
            }
        }
    }

    if (unit == SYS_EUNIT_M)
    {
        cmd = DRV_IOR(CtcMiscCtlReset_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &mcpu_rst));
        SetCtcMiscCtlReset(V, resetMcu_f, &mcpu_rst, p_eunit?0:1);
        cmd = DRV_IOW(CtcMiscCtlReset_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &mcpu_rst));
    }
    else if (unit == SYS_EUNIT_E)
    {
        cmd = DRV_IOR(EcpuSoftReset_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &soft_rst));
        SetEcpuSoftReset(V, cfgResetEcpuCore_f, &soft_rst, p_eunit?0:1);
        cmd = DRV_IOW(EcpuSoftReset_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &soft_rst));
    }
    else if (unit == SYS_EUNIT_S)
    {
        cmd = DRV_IOR(ScpuSoftReset_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &scpu_soft_rst));
        SetScpuSoftReset(V, cfgResetEcpuCore_f, &scpu_soft_rst, p_eunit?0:1);
        cmd = DRV_IOW(ScpuSoftReset_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &scpu_soft_rst));
    }

    p_usw_eunit_master[lchip]->reset_times[unit]++;
    return CTC_E_NONE;
}

int32
sys_tmm_eunit_show_version(uint8 lchip, uint8 eunit_id)
{
    uint8 is_working = 0;
    sys_eunit_emic_ver_t ver;

    sal_memset(&ver, 0, sizeof(ver));

    CTC_MAX_VALUE_CHECK(eunit_id, MCHIP_CAP(SYS_CAP_EUNIT_NUM) - 1);
    CTC_ERROR_RETURN(_sys_tmm_eunit_is_working(lchip, eunit_id, &is_working));
    if (!is_working)
    {
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "eunit[%u] is not working!\n", eunit_id);
        return CTC_E_NOT_READY;
    }

    CTC_ERROR_RETURN(_sys_tmm_eunit_get_emic_ver(lchip, eunit_id, &ver));

    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, 
    "    Eunit %d, EMIC Version %s, Date:%s.\n",
    eunit_id, ver.version, ver.date);

    return CTC_E_NONE;
}

int32
_sys_tmm_eunit_show_status_by_app_id(uint8 lchip, uint8 eunit_id, uint8 app_id)
{
    uint8 is_working = 0;
    uint32 offset = 0;
    uint32 info_offset = 0;
    char* p_str = NULL;
    uint32 value = 0;
    uint8 is_reset = 0;
    sys_usw_eunit_app_info_hdr_t app_name_hdr;
    uint8 app_num=0;
    sys_usw_eunit_app_info_body_t app_info;
    uint8 idx = 0;

    CTC_MAX_VALUE_CHECK(eunit_id, MCHIP_CAP(SYS_CAP_EUNIT_NUM) - 1);

    CTC_ERROR_RETURN(_sys_tmm_eunit_is_reset(lchip, eunit_id, &is_reset));
    CTC_ERROR_RETURN(_sys_tmm_eunit_is_working(lchip, eunit_id, &is_working));
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "EUNIT_ID:%u\n", eunit_id);
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "----------------------------------------\n");
    if (!is_working)
    {
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: %s\n", "Working Status", is_reset ? "Not Worked (uninstall)\n" : "Not Worked (crashed)\n");
        return CTC_E_NONE;
    }
    
    CTC_ERROR_RETURN(_sys_tmm_eunit_misc_int_ctl_read(lchip, eunit_id, SYS_TMM_EUNIT_MISC_INT_FEATURES_ADDR, &offset));
    CTC_ERROR_RETURN(_sys_tmm_eunit_read_data(lchip, offset, (uint32*)&app_name_hdr, 1));
    app_num = app_name_hdr.app_num;

    for(idx = 0; idx<app_num; idx++)
    {
        info_offset = (offset + 4) + idx*sizeof(sys_usw_eunit_app_info_body_t);
        sal_memset(&app_info, 0, sizeof(app_info));
        CTC_ERROR_RETURN(_sys_tmm_eunit_read_data(lchip, info_offset, (uint32*)&app_info, sizeof(sys_usw_eunit_app_info_body_t)/4));

        if(app_info.app_id == app_id)
        {
            break;
        }
    }

    if(idx == app_num)
    {
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "invalid app:%d\n", app_id);
        return CTC_E_INVALID_PARAM;
    }

    p_str = app_info.app_name;
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: %s(%d)\n", "Working Feature", p_str, app_id);

    if (NULL != sal_strstr(p_str, "G8031"))
    {
        CTC_ERROR_RETURN(sys_tmm_eunit_get_cfg(lchip, SYS_EUNIT_CFG_G8031, &value));
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: %s\n", "G8031", value ? "enable" : "disable");
    }
    if (NULL != sal_strstr(p_str, "NPM IM"))
    {
        CTC_ERROR_RETURN(sys_tmm_eunit_get_cfg(lchip, SYS_EUNIT_CFG_NPM_IM, &value));
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: %s\n", "MPLS-IM", value ? "enable" : "disable");
    }
    return CTC_E_NONE;
}

STATIC int32
_sys_tmm_eunit_show_status_by_eunit_id(uint8 lchip, uint8 eunit_id)
{
    uint8 is_working = 0;
    uint32 offset = 0;
    uint32 name_offset = 0;
    uint32 value = 0;
    uint8 is_reset = 0;
    sys_usw_eunit_app_info_hdr_t app_name_hdr;
    uint8 app_id = 0, app_num=0;
    sys_usw_eunit_app_info_body_t app_info;
    sys_eunit_mem_info_t mem_info={0};

    CTC_MAX_VALUE_CHECK(eunit_id, MCHIP_CAP(SYS_CAP_EUNIT_NUM) - 1);

    CTC_ERROR_RETURN(_sys_tmm_eunit_is_reset(lchip, eunit_id, &is_reset));
    CTC_ERROR_RETURN(_sys_tmm_eunit_is_working(lchip, eunit_id, &is_working));
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "EUNIT_ID:%u\n", eunit_id);
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "----------------------------------------\n");
    if (!is_working)
    {
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: %s\n", "Working Status", is_reset ? "Not Worked (uninstall)\n" : "Not Worked (crashed)\n");
        return CTC_E_NONE;
    }
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: %s\n", "Working Status", "Working");

    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: %u kB\n", "Memory Size", eunit_id == SYS_EUNIT_E ? 256 :128);

    CTC_ERROR_RETURN(_sys_tmm_eunit_get_mem_info(lchip, eunit_id, &mem_info));
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: %u B\n", "Total Heap Size", mem_info.total);
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: %u B\n", "Used  Heap Size", mem_info.ram_used);
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: %u B\n", "Max Heap Used Size", mem_info.ram_used_max);

    CTC_ERROR_RETURN(_sys_tmm_eunit_misc_int_ctl_read(lchip, eunit_id, SYS_TMM_EUNIT_MISC_INT_CMD_MEM_ADDR, &value));
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: 0x%x\n", "Config Pcie Addr", value);

    CTC_ERROR_RETURN(_sys_tmm_eunit_misc_int_ctl_read(lchip, eunit_id, SYS_TMM_EUNIT_MISC_INT_DBG_BUF_ADDR, &value));
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: 0x%x\n", "Debug Pcie Addr", value);

    CTC_ERROR_RETURN(_sys_tmm_eunit_misc_int_ctl_read(lchip, eunit_id, SYS_TMM_EUNIT_MISC_INT_ALIVE_CNT, &offset));
    CTC_ERROR_RETURN(_sys_tmm_eunit_read_data(lchip, offset, &value, 1));
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: %u\n", "Chip Alive Count", value);

    CTC_ERROR_RETURN(_sys_tmm_eunit_misc_int_ctl_read(lchip, eunit_id, SYS_TMM_EUNIT_MISC_INT_FEATURES_ADDR, &offset));
    CTC_ERROR_RETURN(_sys_tmm_eunit_read_data(lchip, offset, (uint32*)&app_name_hdr, 1));
    app_num = app_name_hdr.app_num;
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: %u\n", "App Num", app_num);
    
    for(app_id = 0; app_id<app_num; app_id++)
    {
        name_offset = (offset + 4) + app_id*sizeof(sys_usw_eunit_app_info_body_t);

        sal_memset(&app_info, 0, sizeof(app_info));

        CTC_ERROR_RETURN(_sys_tmm_eunit_read_data(lchip, name_offset, (uint32*)&app_info, sizeof(sys_usw_eunit_app_info_body_t)/4));
        if(!sal_strlen(app_info.app_name))
        {
            continue;
        }
        
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: %s(%d)\n", "Working Feature", app_info.app_name, app_info.app_id);
    }
    CTC_ERROR_RETURN(_sys_tmm_eunit_dump_thread_info(lchip, eunit_id));
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\n");

    return CTC_E_NONE;
}

int32
_sys_tmm_eunit_show_status_by_all(uint8 lchip)
{
    McpuMiscIntInfo0_m misc_info;
    uint32 cmd = 0;
    uint32 value = 0;
    uint8 eunit_id;
    uint8 is_working = 0;
    uint8 is_reset = 0;

    for (eunit_id = 0; eunit_id <= SYS_EUNIT_S; eunit_id++)
    {
        CTC_ERROR_RETURN(_sys_tmm_eunit_is_reset(lchip, eunit_id, &is_reset));
        CTC_ERROR_RETURN(_sys_tmm_eunit_is_working(lchip, eunit_id, &is_working));
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "EUNIT_ID:%u\n", eunit_id);
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "----------------------------------------\n");
        if (!is_working)
        {
            SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: %s\n", "Working Status", is_reset ? "Not Worked (uninstall)\n" :"Not Worked (crashed)\n");
        }
        else
        {
            SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: %s\n", "Working Status", "Working\n");
        }
    }
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "EUNIT_ID:2\n");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "----------------------------------------\n");

    cmd = DRV_IOR(McpuMiscIntInfo0_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, (M_UNTT_MAX_NUM - 1), cmd, &misc_info));
    value = GetMcpuMiscIntInfo0(V,miscIntInfo0_f, &misc_info);
    if (!value)
    {
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "MCPU(MISC) Not Worked!\n");
    }
    else
    {
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "MCPU(MISC) Wroking:\n");
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: %s\n", "ToD INTF(Flex)", CTC_IS_BIT_SET(value, M_UNTT_TOD_ENABLE) ? "Enable" : "Disable");
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: %s\n", "SYNC INTF", CTC_IS_BIT_SET(value, M_UNTT_SYNC_ENABLE) ? "Enable" : "Disable");
    }

    return CTC_E_NONE;
}

int32
sys_tmm_eunit_show_status(uint8 lchip, uint8 level, void* p_params)
{
    uint8 eunit_id = 0;
    uint8 app_id = 0;
    sys_usw_eunit_status_params_t *params;

    params = (sys_usw_eunit_status_params_t*)p_params;
    switch(level)
    {
        case 0:
            CTC_ERROR_RETURN(_sys_tmm_eunit_show_status_by_all(lchip));
            break;
        case 1:
            CTC_PTR_VALID_CHECK(p_params);
            eunit_id = params->eunit_id;
            CTC_ERROR_RETURN(_sys_tmm_eunit_show_status_by_eunit_id(lchip, eunit_id));
            break;
        case 2:
            CTC_PTR_VALID_CHECK(p_params);
            eunit_id = params->eunit_id;
            app_id = params->app_id;
            CTC_ERROR_RETURN(_sys_tmm_eunit_show_status_by_app_id(lchip, eunit_id, app_id));
            break;
        default:
            return CTC_E_INVALID_PARAM;
    }

    return CTC_E_NONE;
}

int32
sys_tmm_eunit_show_dma_stats(uint8 lchip, uint8 eunit_id)
{
    /*
     even index is good stats;
     odd index is bad stats;
    */
    EcpuPktRxStats_m rx_stats;
    EcpuPktTxStats_m tx_stats;
    uint16 idx = 0;
    uint8 ring = 0;
    uint32 cmd = 0;
    uint64 bytes = 0;
    uint64 count = 0;
    uint8 is_reset = 0;

    CTC_MAX_VALUE_CHECK(eunit_id, SYS_EUNIT_S);
    CTC_ERROR_RETURN(_sys_tmm_eunit_is_reset(lchip, eunit_id, &is_reset));
    if (is_reset)
    {
        return CTC_E_NONE;
    }

    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%s Rx Stats:\n", SYS_EUNIT_E == eunit_id ? "ECPU" : "SCPU");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-----------------------------------------------------------------------------------\n");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-6s%-21s%-21s%-21s%-21s\n", "Ring", "GoodPktCnt", "GoodPktByte", "BadPktCnt", "BadPktByte");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-----------------------------------------------------------------------------------\n");

    for (ring = 0; ring < SYS_TMM_EUNIT_DMA_RX_RING_NUM; ring++)
    {
        idx = ring * 2;
        cmd = DRV_IOR(SYS_EUNIT_E == eunit_id ? EcpuPktRxStats_t : ScpuPktRxStats_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, idx, cmd, &rx_stats));
        count = GetEcpuPktRxStats(V, frameCntHi_f, &rx_stats);
        count <<= 32;
        count |= GetEcpuPktRxStats(V, frameCntLo_f, &rx_stats);
        bytes = GetEcpuPktRxStats(V, byteCntHi_f, &rx_stats);
        bytes <<= 32;
        bytes |= GetEcpuPktRxStats(V, byteCntLo_f, &rx_stats);
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-6u%-21"PRIu64"%-21"PRIu64, ring, count, bytes);

        CTC_ERROR_RETURN(DRV_IOCTL(lchip, idx + 1, cmd, &rx_stats));
        count = GetEcpuPktRxStats(V, frameCntHi_f, &rx_stats);
        count <<= 32;
        count |= GetEcpuPktRxStats(V, frameCntLo_f, &rx_stats);
        bytes = GetEcpuPktRxStats(V, byteCntHi_f, &rx_stats);
        bytes <<= 32;
        bytes |= GetEcpuPktRxStats(V, byteCntLo_f, &rx_stats);
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-21"PRIu64"%-21"PRIu64"\n", count, bytes);
    }
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\n");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%s Tx Stats:\n", SYS_EUNIT_E == eunit_id ? "ECPU" : "SCPU");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-----------------------------------------------------------------------------------\n");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-6s%-21s%-21s%-21s%-21s\n", "Ring", "GoodPktCnt", "GoodPktByte", "BadPktCnt", "BadPktByte");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-----------------------------------------------------------------------------------\n");

    for (ring = 0; ring < SYS_TMM_EUNIT_DMA_TX_RING_NUM; ring++)
    {
        idx = ring * 2;
        cmd = DRV_IOR(SYS_EUNIT_E == eunit_id ? EcpuPktTxStats_t : ScpuPktTxStats_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, idx, cmd, &tx_stats));
        count = GetEcpuPktTxStats(V, frameCntHi_f, &tx_stats);
        count <<= 32;
        count |= GetEcpuPktTxStats(V, frameCntLo_f, &tx_stats);
        bytes = GetEcpuPktTxStats(V, byteCntHi_f, &tx_stats);
        bytes <<= 32;
        bytes |= GetEcpuPktTxStats(V, byteCntLo_f, &tx_stats);
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-6u%-21"PRIu64"%-21"PRIu64, ring, count, bytes);

        CTC_ERROR_RETURN(DRV_IOCTL(lchip, idx + 1, cmd, &tx_stats));
        count = GetEcpuPktTxStats(V, frameCntHi_f, &tx_stats);
        count <<= 32;
        count |= GetEcpuPktTxStats(V, frameCntLo_f, &tx_stats);
        bytes = GetEcpuPktTxStats(V, byteCntHi_f, &tx_stats);
        bytes <<= 32;
        bytes |= GetEcpuPktTxStats(V, byteCntLo_f, &tx_stats);
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-21"PRIu64"%-21"PRIu64"\n", count, bytes);
    }

    return CTC_E_NONE;
}

int32
sys_tmm_eunit_clear_dma_stats(uint8 lchip, uint8 eunit_id)
{
    EcpuPktRxStats_m rx_stats;
    EcpuPktTxStats_m tx_stats;
    uint32 cmd =0;
    uint16 idx = 0;
    uint8 ring = 0;
    uint8 is_reset = 0;

    CTC_MAX_VALUE_CHECK(eunit_id, SYS_EUNIT_S);
    CTC_ERROR_RETURN(_sys_tmm_eunit_is_reset(lchip, eunit_id, &is_reset));
    if (is_reset)
    {
        return CTC_E_NONE;
    }

    sal_memset(&rx_stats, 0, sizeof(EcpuPktRxStats_m));
    sal_memset(&tx_stats, 0, sizeof(EcpuPktTxStats_m));

    for (ring = 0; ring < SYS_TMM_EUNIT_DMA_RX_RING_NUM; ring++)
    {
        idx = ring * 2;
        cmd = DRV_IOW(SYS_EUNIT_E == eunit_id ? EcpuPktRxStats_t : ScpuPktRxStats_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, idx, cmd, &rx_stats));
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, idx + 1, cmd, &rx_stats));
    }

    for (ring = 0; ring < SYS_TMM_EUNIT_DMA_TX_RING_NUM; ring++)
    {
        idx = ring * 2;
        cmd = DRV_IOW(SYS_EUNIT_E == eunit_id ? EcpuPktTxStats_t : ScpuPktTxStats_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, idx, cmd, &rx_stats));
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, idx + 1, cmd, &rx_stats));
    }

    return CTC_E_NONE;
}


int32
sys_tmm_eunit_show_dma_status(uint8 lchip, uint8 eunit_id)
{
    uint32 cmd = 0;
    uint8 ring = 0;
    uint32 vld_num = 0;
    uint32 ring_depth = 0;
    uint32 desc_base = 0;
    uint32 desc_end = 0;
    uint32 data_base = 0;
    DsDesc_m ds_desc;
    char *dma_rx[SYS_TMM_EUNIT_DMA_RX_RING_NUM] = {"PktRx0","PktRx1","PktRx2","PktRx3"};
    char *dma_tx[SYS_TMM_EUNIT_DMA_TX_RING_NUM] = {"PktTx0","PktTx1","PktTx2","PktTx3"};
    char *dma_info_str[SYS_TMM_ECPU_DMA_INFO_RING_NUM] = {"Info0","Info1","Info2","Info3","Info4","Info5","Info6","Info7"};
    sys_eunit_dma_info_t dma_info;
    PktTxDescNum_m tx_desc_num;
    PktTxDmaCtl_m tx_dma_ctl;
    PktTxDescCfg_m tx_desc_cfg;
    PktRxDescNum_m rx_desc_num;
    PktRxDmaCtl_m rx_dma_ctl;
    PktRxDescCfg_m rx_desc_cfg;
    InfoDmaCtl_m info_dma_ctl;
    InfoDescCfg_m info_desc_cfg;
    InfoDescNum_m info_desc_num;

    CTC_MAX_VALUE_CHECK(eunit_id, SYS_EUNIT_S);

    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-6s%-10s%-10s%-7s%-7s%-15s  %-15s\n","Chan", "Function", "ValidNum","CurIdx", "Depth", "DescBase", "DataBase");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-------------------------------------------------------------\n");

    /* get dma information from ECPU/SCPU */
    CTC_ERROR_RETURN(_sys_tmm_eunit_get_dma_info(lchip, eunit_id, &dma_info));

    /* show DmaPktRx chan status */
    for (ring = 0; ring < SYS_TMM_EUNIT_DMA_RX_RING_NUM; ring++)
    {
        if (!CTC_IS_BIT_SET(dma_info.ring_bmp, ring))
        {
            continue;
        }
        cmd = DRV_IOR(SYS_EUNIT_E == eunit_id ? PktRxDmaCtl_t : ScpuPktRxDmaCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, ring, cmd, &rx_dma_ctl));
        if (GetPktRxDmaCtl(V, dmaEn_f, &rx_dma_ctl))
        {
            cmd = DRV_IOR(SYS_EUNIT_E == eunit_id ? PktRxDescNum_t : ScpuPktRxDescNum_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, ring, cmd, &rx_desc_num));
            vld_num = GetPktRxDescNum(V, descVldNum_f, &rx_desc_num);

            cmd = DRV_IOR(SYS_EUNIT_E == eunit_id ? PktRxDescCfg_t : ScpuPktRxDescCfg_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, ring, cmd, &rx_desc_cfg));
            desc_base = GetPktRxDescCfg(V, descStartPtr_f, &rx_desc_cfg);
            desc_end = GetPktRxDescCfg(V, descEndPtr_f, &rx_desc_cfg);
            if (SYS_EUNIT_E == eunit_id)
            {
                desc_base = SYS_TMM_ECPU_ADDR_MAP(desc_base << 2);
                desc_end = SYS_TMM_ECPU_ADDR_MAP(desc_end << 2); 
            }
            else
            {
                desc_base = SYS_TMM_SCPU_ADDR_MAP(desc_base << 2);
                desc_end = SYS_TMM_SCPU_ADDR_MAP(desc_end << 2); 
            }
            ring_depth = (desc_end - desc_base)/sizeof(DsDesc_m);

            /* read the first descriptor from desc_base to get data_base */
            CTC_ERROR_RETURN(_sys_tmm_eunit_read_data(lchip, desc_base, (uint32*)&ds_desc, sizeof(DsDesc_m)/sizeof(uint32)));
            data_base = GetDsDesc(V, memAddr_f, &ds_desc) << 4;
            SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-6u%-10s%-10u%-7u%-7u0x%-13x  0x%-13x\n",
            ring+SYS_TMM_EUNIT_DMA_RX_RING_BASE, dma_rx[ring], vld_num, dma_info.desc_cur_idx[ring], ring_depth, desc_base,
            (SYS_EUNIT_E == eunit_id) ? SYS_TMM_ECPU_ADDR_MAP(data_base):SYS_TMM_SCPU_ADDR_MAP(data_base));
        }
    }

    /* show DmaPktTx chan status */
    for (ring = 0; ring < SYS_TMM_EUNIT_DMA_TX_RING_NUM; ring++)
    {
        if (!CTC_IS_BIT_SET(dma_info.ring_bmp, ring+SYS_TMM_EUNIT_DMA_TX_RING_BASE))
        {
            continue;
        }
        cmd = DRV_IOR(SYS_EUNIT_E == eunit_id ? PktTxDmaCtl_t : ScpuPktTxDmaCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, ring, cmd, &tx_dma_ctl));
        if (GetPktTxDmaCtl(V, dmaEn_f, &tx_dma_ctl))
        {
            cmd = DRV_IOR(SYS_EUNIT_E == eunit_id ? PktTxDescNum_t : ScpuPktTxDescNum_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, ring, cmd, &tx_desc_num));
            vld_num = GetPktTxDescNum(V, descVldNum_f, &tx_desc_num);

            cmd = DRV_IOR(SYS_EUNIT_E == eunit_id ? PktTxDescCfg_t : ScpuPktTxDescCfg_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, ring, cmd, &tx_desc_cfg));
            desc_base = GetPktTxDescCfg(V, descStartPtr_f, &tx_desc_cfg);
            desc_end = GetPktTxDescCfg(V, descEndPtr_f, &tx_desc_cfg);
            if (SYS_EUNIT_E == eunit_id)
            {
                desc_base = SYS_TMM_ECPU_ADDR_MAP(desc_base << 2);
                desc_end = SYS_TMM_ECPU_ADDR_MAP(desc_end << 2); 
            }
            else
            {
                desc_base = SYS_TMM_SCPU_ADDR_MAP(desc_base << 2);
                desc_end = SYS_TMM_SCPU_ADDR_MAP(desc_end << 2); 
            }
            ring_depth = (desc_end - desc_base)/sizeof(DsDesc_m);

            /* read the first descriptor from desc_base to get data_base */
            CTC_ERROR_RETURN(_sys_tmm_eunit_read_data(lchip, desc_base, (uint32*)&ds_desc, sizeof(DsDesc_m)/sizeof(uint32)));
            data_base = GetDsDesc(V, memAddr_f, &ds_desc) << 4;
            SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-6u%-10s%-10u%-7u%-7u0x%-13x  0x%-13x\n",
            ring+SYS_TMM_EUNIT_DMA_TX_RING_BASE, dma_tx[ring], vld_num, dma_info.desc_cur_idx[ring+SYS_TMM_EUNIT_DMA_TX_RING_BASE], ring_depth, desc_base, data_base);
        }
    }

    /* show DmaInfo chan status */
    for (ring = 0; ring < SYS_TMM_ECPU_DMA_INFO_RING_NUM; ring++)
    {
        if (!CTC_IS_BIT_SET(dma_info.ring_bmp, ring+SYS_TMM_ECPU_DMA_INFO_RING_BASE))
        {
            continue;
        }
        cmd = DRV_IOR(InfoDmaCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, ring, cmd, &info_dma_ctl));
        if (GetPktTxDmaCtl(V, dmaEn_f, &info_dma_ctl))
        {
            cmd = DRV_IOR(InfoDescNum_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, ring, cmd, &info_desc_num));
            vld_num = GetInfoDescNum(V, descVldNum_f, &info_desc_num);

            cmd = DRV_IOR(InfoDescCfg_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, ring, cmd, &info_desc_cfg));
            desc_base = GetInfoDescCfg(V, descStartPtr_f, &info_desc_cfg);
            desc_end = GetInfoDescCfg(V, descEndPtr_f, &info_desc_cfg);
            desc_base = SYS_TMM_ECPU_ADDR_MAP(desc_base << 2);
            desc_end = SYS_TMM_ECPU_ADDR_MAP(desc_end << 2); 
            ring_depth = (desc_end - desc_base)/sizeof(DsDesc_m);

            /* read the first descriptor from desc_base to get data_base */
            CTC_ERROR_RETURN(_sys_tmm_eunit_read_data(lchip, desc_base, (uint32*)&ds_desc, sizeof(DsDesc_m)/sizeof(uint32)));
            data_base = GetDsDesc(V, memAddr_f, &ds_desc) << 4;
            SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-6u%-10s%-10u%-7u%-7u0x%-13x  0x%-13x\n",
            ring+SYS_TMM_ECPU_DMA_INFO_RING_BASE, dma_info_str[ring], vld_num, dma_info.desc_cur_idx[ring+SYS_TMM_ECPU_DMA_INFO_RING_BASE], ring_depth, desc_base, data_base);
        }
    }

    return CTC_E_NONE;
}


int32
sys_tmm_eunit_show_dma_desc(uint8 lchip,      uint8 eunit_id, uint8 chan_id, uint32 start_idx, uint32 end_idx)
{
    uint32 desc_base = 0;
    uint32 data_addr = 0;
    uint32 desc_end = 0;
    uint32 ring_depth = 0;
    uint32 cmd;
    uint32 index;
    DsDesc_m ds_desc;
    uint32 timestamp[2] = {0};
    uint64 tm_ns = 0;
    uint32 tm_s = 0;
    PktTxDmaCtl_m tx_dma_ctl;
    PktTxDescCfg_m tx_desc_cfg;
    PktRxDmaCtl_m rx_dma_ctl;
    PktRxDescCfg_m rx_desc_cfg;
    InfoDmaCtl_m info_dma_ctl;
    InfoDescCfg_m info_desc_cfg;

 	CTC_MAX_VALUE_CHECK(eunit_id, SYS_EUNIT_S);
    CTC_MAX_VALUE_CHECK(start_idx, end_idx);
    if (SYS_EUNIT_E == eunit_id)
    {
        CTC_MAX_VALUE_CHECK(chan_id, SYS_TMM_ECPU_DMA_RING_NUM-1);
    }
    else
    {
        CTC_MAX_VALUE_CHECK(chan_id, SYS_TMM_SCPU_DMA_RING_NUM-1);
    }

    /* 1. get current chan Desc addr base*/
    if (chan_id < SYS_TMM_EUNIT_DMA_TX_RING_BASE)
    {
        cmd = DRV_IOR(SYS_EUNIT_E == eunit_id ? PktRxDmaCtl_t : ScpuPktRxDmaCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, chan_id - SYS_TMM_EUNIT_DMA_RX_RING_BASE, cmd, &rx_dma_ctl));
        if (GetPktRxDmaCtl(V, dmaEn_f, &rx_dma_ctl))
        {
            cmd = DRV_IOR(SYS_EUNIT_E == eunit_id ? PktRxDescCfg_t : ScpuPktRxDescCfg_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, chan_id - SYS_TMM_EUNIT_DMA_RX_RING_BASE, cmd, &rx_desc_cfg));
            desc_base = GetPktRxDescCfg(V, descStartPtr_f, &rx_desc_cfg);
            desc_end = GetPktRxDescCfg(V, descEndPtr_f, &rx_desc_cfg);
            if (SYS_EUNIT_E == eunit_id)
            {
                desc_base = SYS_TMM_ECPU_ADDR_MAP(desc_base << 2);
                desc_end = SYS_TMM_ECPU_ADDR_MAP(desc_end << 2); 
            }
            else
            {
                desc_base = SYS_TMM_SCPU_ADDR_MAP(desc_base << 2);
                desc_end = SYS_TMM_SCPU_ADDR_MAP(desc_end << 2); 
            }
            ring_depth = (desc_end - desc_base)/sizeof(DsDesc_m);
            CTC_MAX_VALUE_CHECK(end_idx, ring_depth-1);
        }
        else
        {
            SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Current chan is not enable\n");
            return CTC_E_NONE;
        }
    }
    else if (chan_id < SYS_TMM_ECPU_DMA_REG_RD_RING_BASE)
    {
        cmd = DRV_IOR(SYS_EUNIT_E == eunit_id ? PktTxDmaCtl_t : ScpuPktTxDmaCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, chan_id - SYS_TMM_EUNIT_DMA_TX_RING_BASE, cmd, &tx_dma_ctl));
        if (GetPktTxDmaCtl(V, dmaEn_f, &tx_dma_ctl))
        {
            cmd = DRV_IOR(SYS_EUNIT_E == eunit_id ? PktTxDescCfg_t : ScpuPktTxDescCfg_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, chan_id - SYS_TMM_EUNIT_DMA_TX_RING_BASE, cmd, &tx_desc_cfg));
            desc_base = GetPktTxDescCfg(V, descStartPtr_f, &tx_desc_cfg);
            desc_end = GetPktTxDescCfg(V, descEndPtr_f, &tx_desc_cfg);
            if (SYS_EUNIT_E == eunit_id)
            {
                desc_base = SYS_TMM_ECPU_ADDR_MAP(desc_base << 2);
                desc_end = SYS_TMM_ECPU_ADDR_MAP(desc_end << 2); 
            }
            else
            {
                desc_base = SYS_TMM_SCPU_ADDR_MAP(desc_base << 2);
                desc_end = SYS_TMM_SCPU_ADDR_MAP(desc_end << 2); 
            }
            ring_depth = (desc_end - desc_base)/sizeof(DsDesc_m);
            CTC_MAX_VALUE_CHECK(end_idx, ring_depth-1);
        }
        else
        {
            SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Current chan is not enable\n");
            return CTC_E_NONE;
        }
    }
    else if (chan_id >= SYS_TMM_ECPU_DMA_INFO_RING_BASE)
    {
        cmd = DRV_IOR(InfoDmaCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, chan_id - SYS_TMM_ECPU_DMA_INFO_RING_BASE, cmd, &info_dma_ctl));
        if (GetInfoDmaCtl(V, dmaEn_f, &info_dma_ctl))
        {
            cmd = DRV_IOR(InfoDescCfg_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, chan_id - SYS_TMM_ECPU_DMA_INFO_RING_BASE, cmd, &info_desc_cfg));
            desc_base = GetInfoDescCfg(V, descStartPtr_f, &info_desc_cfg);
            desc_end = GetInfoDescCfg(V, descEndPtr_f, &info_desc_cfg);
            desc_base = SYS_TMM_ECPU_ADDR_MAP(desc_base << 2);
            desc_end = SYS_TMM_ECPU_ADDR_MAP(desc_end << 2); 
            ring_depth = (desc_end - desc_base)/sizeof(DsDesc_m);
            CTC_MAX_VALUE_CHECK(end_idx, ring_depth-1);
        }
        else
        {
            SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Current chan is not enable\n");
            return CTC_E_NONE;
        }
    }
    else
    {
        return CTC_E_NONE;
    }

    /* 2. dump desc */
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\n");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " %-22s", "P-Pause");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-26s", "DER-Data Error");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-26s\n", "D-Descriptor Done");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " %-22s", "ER-Total Error");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-26s", "CSize-Config Size");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-26s\n", "S-Descriptor SOP");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " %-22s", "RSize-Actual Size");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-26s", "T-Descriptor Timeout");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-26s\n", "M-Interrupt Mask");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " %-22s", "E-Descriptor EOP");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-26s", "DS-DataStruct(For Reg)");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-26s\n", "DeE-Descriptor Error");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " %-38s", "DAddr-Data Memory Address");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-27s\n", "V-Descriptor Valid");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\n");

    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-4s %-14s %-14s %-8s %-8s %-2s %-1s %-1s %-2s %-3s %-3s %-1s %-1s %-1s %-1s %-1s %-10s %-10s\n",
        "IDX", "DescAddr", "DAddr", "RSize", "CSize", "DS", "D", "V", "ER", "DER", "DeE", "T", "P", "M", "E", "S", "TS(ns)", "TS(s)");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "---------------------------------------------------------------------------------------------------\n");

    for (index = start_idx; index <= end_idx; index++)
    {
        CTC_ERROR_RETURN(_sys_tmm_eunit_read_data(lchip, desc_base, (uint32*)&ds_desc, sizeof(DsDesc_m)/sizeof(uint32)));
        GetDsDesc(A, timestamp_f, &ds_desc, timestamp);
        tm_ns = timestamp[1];
        tm_ns = (tm_ns << 32);
        tm_ns |= timestamp[0];

        tm_s = tm_ns/1000000000;
        tm_ns = tm_ns - tm_s*1000000000;
        data_addr = GetDsDesc(V, memAddr_f, &ds_desc)<<4;

        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-4d 0x%-12x 0x%-12x %-8d %-8d %-2d %-1d %-1d %-2d %-3d %-3d %-1d %-1d %-1d %-1d %-1d 0x%-8x 0x%-8x\n",
        index,
        desc_base,
        (SYS_EUNIT_E == eunit_id)?SYS_TMM_ECPU_ADDR_MAP(data_addr):SYS_TMM_SCPU_ADDR_MAP(data_addr),
        GetDsDesc(V, realSize_f, &ds_desc),
        GetDsDesc(V, cfgSize_f, &ds_desc),
        GetDsDesc(V, dataStruct_f, &ds_desc),
        GetDsDesc(V, done_f, &ds_desc),
        GetDsDesc(V, valid_f, &ds_desc),
        GetDsDesc(V, error_f, &ds_desc),
        GetDsDesc(V, dataError_f, &ds_desc),
        GetDsDesc(V, descError_f, &ds_desc),
        GetDsDesc(V, u2_info_timeout_f, &ds_desc),
        GetDsDesc(V, pause_f, &ds_desc),
        GetDsDesc(V, intrMask_f, &ds_desc),
        GetDsDesc(V, u1_pkt_eop_f, &ds_desc),
        GetDsDesc(V, u1_pkt_sop_f, &ds_desc),
        (uint32)tm_ns,
        tm_s
        );
        desc_base += sizeof(DsDesc_m);
    }

    return CTC_E_NONE;
}

#endif
#endif
